package tcpFirmware;

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;

public class OKServer {
    ServerSocket serverSocket;
    ArrayList<Thread> threads;
    static HashMap<String,HashMap<String,Object>> methodMap;

    OKServer(ServerSocket serverSocket){
        this.serverSocket=serverSocket;
        this.threads = new ArrayList<>();
        methodMap = MenuScanner.getScanMenus();
    }


    public static void main(String[] args) {
        OKServer okServer = OKServer.getInstance();
        assert okServer != null;
        okServer.go();
    }


    public static OKServer getInstance() {
        try {
            ServerSocket serverSocket = new ServerSocket(10086);
            return new OKServer(serverSocket);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * go方法，循环监听，把连接请求放入子线程处理
     */

    public final void go(){
        while(true){
            try {
                Socket socket = this.serverSocket.accept();
                Thread i = new Thread(new Inner(socket));
                threads.add(i);
                i.start();
                if(threads.size()>50){
                    threads.get(0).stop();
                    threads.remove(0);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    static class Inner implements Runnable{


        Socket socket;
        HashMap<String,String> formData;
        HashMap<String,String> lHeader;
        byte[] binaryData;

        Inner(Socket socket){
            this.socket = socket;
        }

        @Override
        public void run() {
            try {
                InputStream inputStream = socket.getInputStream();
                StringBuilder builder = new StringBuilder();

                //读取偏移量---首部长度
                byte[] offset = new byte[4];
                inputStream.read(offset);
                int headerLen = Integer.parseInt(new String(offset));

                //读取首部
                byte[] headerBytes = new byte[headerLen];
                inputStream.read(headerBytes);
                String header = new String(headerBytes);

                //解包首部字段和数据部分
                unpacked(header,inputStream);

            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        public void unpacked(String h,InputStream inputStream) throws IOException {
            String[] headerMap = h.split("\r\n");
            HashMap<String,String> header = new HashMap<>();
            for (String s : headerMap) {
                String[] map = s.split(":");
                header.put(map[0], map[1]);
            }
            System.out.println(header);
            lHeader=header;
            //首部解包完成，开始解包数据部分

            byte[] dataBytes = new byte[Integer.parseInt(header.get("content-length"))];
            inputStream.read(dataBytes);
            if(header.get("content-type").equals(Type.text.type)){
                String[] bodyMap = new String(dataBytes).split("\r\n");
                HashMap<String,String> body = new HashMap<>();
                for(String s:bodyMap){
                    String[] form = s.split(":");
                    body.put(form[0],form[1]);
                }
                System.out.println(body);
                formData=body;
            }

            //在对应方法中处理完数据后向前端响应结果，可参考如下示例，sendResponse目前有两个方法，一个发文本，一个发二进制字节

            HashMap<String,Object> routeMap = OKServer.methodMap.get(header.get("route"));
            if (routeMap==null){ResponseBody.sendNotFound(socket);}
            else {
                Method j =(Method) routeMap.get("method");
                try {
                    if(header.get("content-type").equals(Type.text.type))
                        j.invoke(routeMap.get("instance"),socket,header,formData);
                    else
                        j.invoke(routeMap.get("instance"),socket,header,dataBytes);
                } catch (IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }

        public final HashMap<String,String> getHeader(){
            return lHeader;
        }

        public final HashMap<String,String> getFormData(){
            return formData;
        }

        public final byte[] getBinaryData(){return binaryData;}

    }
}
